package com.gao.shiro.demo.sessionfilter;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * @author gaofeng
 * @date 2022-07-22
 */
@Slf4j
public class JwtFilter extends BasicHttpAuthenticationFilter {

	/**
	 * 如果请求头带有token，校验token，没有直接放行
	 * @param request
	 * @param response
	 * @param mappedValue
	 * @return
	 */
	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
		// 判断请求头是否带有token
		if (isLoginAttempt(request, response)) {

			// 有，进入executeLogin登录，并验证token的正确性
			try {
				executeLogin(request, response) ;
			} catch (Exception e) {
				e.printStackTrace();
				responseError(response, e.getMessage()) ;
			}
		}
		// 如果没有，可能是执行登录操作/游客访问状态，直接放行
		return true ;
	}

	@Override
	protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
		return getTokenFromRequest(request) != null ;
	}

	@Override
	protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
		String token = getTokenFromRequest(request) ;
		JwtToken jwtToken = new JwtToken(token) ;
		// 提交给realm进行登入，如果错误，会抛出异常
		getSubject(request, response).login(jwtToken);
		// 没有抛异常，代表登录成功！
		return true ;
	}

	// 非法请求将跳转到 "/unauthorized/**"
	private void responseError(ServletResponse response, String message) {
		try {
			HttpServletResponse resp = (HttpServletResponse) response;
			// 设置编码，否则中文字符在重定向时会变为空字符串
			message = URLEncoder.encode(message, "UTF-8");
			resp.sendRedirect("/unauthorized/" + message);
		} catch (IOException e) {
			log.error("Error! {}", e.getMessage());
		}
	}

	// 从请求中获取 token
	private String getTokenFromRequest(ServletRequest request) {
		HttpServletRequest req = (HttpServletRequest) request;
		return req.getHeader("Token");
	}
}